

--for show events in chatframe (debug)
local CS_Event_Debug = false

--local constants
local CS_Vars_Loaded = false
local CURR_COMBOPOINTS = 0
local EXECUTE_TIMER = GetTime()
local WINDFURY_TIMER = GetTime()
local CRITICAL_TIMER = GetTime()
local HEALCRIT_TIMER = GetTime()
local KILLPRAISE_TIMER = GetTime()


--globals
CS_MUSIC_FADER_ON = false
CS_STARTER_MESSAGE_RUNNABLE_BOOLEN = false
CS_INITALIZED_BOOLEN = false
CS_LAST_TARGETNAME = ""
CS_UpdateInterval = 0.1

--default config
local default_config =		{
						["STARTSOUND"] = 1,				--1
						["ENABLE"] = 1,					--2
						["ENTERCOMBAT"] = 1,			--3
						["LEAVECOMBAT"] = 1,			--4
						["MUSIC"] = 1,					--5
						["CRITS"] = 1,					--6
						["EXECUTE"] = 1,					--7
						["GETCRITS"] = 1,				--8
						["KILLPRAISE"] = 1,				--9
						["TARGETDODGE"] = 1,			--10
						["DEATH"] = 1,					--11
						["DODGE"] = 1,					--12
						["PARRY"] = 1,					--13
						["HEALCRITS"] = 1,				--14
						["WINDFURY"] = 1,				--15
						["COMBOPOINTS"] = 1,			--16
						["COMBOFULL"] = 1				--17
						}

-----------------------------

--FUNCTIONS

--Displays a message to chat
function CS_Message(msg)
	if( DEFAULT_CHAT_FRAME ) then
		DEFAULT_CHAT_FRAME:AddMessage(msg)
	end
end

--called when its loaded
function CS_OnLoad()
	-- register startup events
	this:RegisterEvent("VARIABLES_LOADED")
	this:RegisterEvent("ADDON_LOADED")
	--onupdate
	this.TimeSinceLastUpdate = 0
end

--show the option menu
function CS_ShowMenu()
	PlaySound("igMainMenuOpen")
	ShowUIPanel(getglobal(CONFIG_FRAME))
--	CombatSoundConfigFrame:Show()
end

--hide the option menu
function CS_HideMenu()
	PlaySound("igMainMenuClose")
	HideUIPanel(getglobal(CONFIG_FRAME))
--	CombatSoundConfigFrame:Hide()
end

--set up a default config
function CS_Config_NewPlayer(PlayerName)
	CSConfig[PlayerName] = CS_tablecopier(default_config)
	CS_Message(CS_NEW_CONFIG.."|cffffff20"..PlayerName.."|cffffffff")
end

--get or create a config, based on the current player
function CS_Config_GetPlayer()
	if (not CSConfig[CS_Player]) then
		CS_Config_NewPlayer(CS_Player)
	end
	return CSConfig[CS_Player]
end

--get a value from player config
function CS_Get(option)
	return CS_PlayerData[option]
end

--set a value in player config
function CS_Set(option, newVal)
	CS_PlayerData[option] = newVal
end

--copy a whole table
function CS_tablecopier(t)		--return a copy of the table t
	local new = {}				--create a new table
	local i, v = next(t, nil)			--i is an index of t, v = t[i]
	while i do
		if type(v) == "table" then
  			v=CS_tablecopier(v)
	  	end 
		new[i] = v
		i, v = next(t, i)			--get next index
	end
return new
end

--get enabled status
function CS_ISE(text)
	--we set the flag by first checkbutton's enable/disable status
	if (CS_Get("ENABLE")) then
		ENABLED = text.."|cffff8888Enabled."
	else
		ENABLED = text.."|cffff8888Disabled."
	end
	return ENABLED
end

-----------------------------

--set player config and initialize
function CS_Initialize()
	
	--registering events
	this:RegisterEvent("ADDON_LOADED")
	this:RegisterEvent("VARIABLES_LOADED")
	this:RegisterEvent("PLAYER_ENTERING_WORLD")
	this:RegisterEvent("PLAYER_ENTER_COMBAT")
	this:RegisterEvent("PLAYER_REGEN_ENABLED")
	this:RegisterEvent("PLAYER_LEAVE_COMBAT")
	this:RegisterEvent("PLAYER_REGEN_DISABLED")
	this:RegisterEvent("PLAYER_AURAS_CHANGED")
	this:RegisterEvent("UNIT_AURA")
	this:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE")
	this:RegisterEvent("CHAT_MSG_COMBAT_SELF_HITS")
	this:RegisterEvent("UNIT_HEALTH")
	this:RegisterEvent("UNIT_COMBAT")
	this:RegisterEvent("CHAT_MSG_COMBAT_HOSTILE_DEATH")
	this:RegisterEvent("CHAT_MSG_COMBAT_SELF_MISSES")
	this:RegisterEvent("PLAYER_TARGET_CHANGED")
	this:RegisterEvent("PLAYER_DEAD")
	this:RegisterEvent("PLAYER_COMBO_POINTS")
	this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS")
	this:RegisterEvent("CHAT_MSG_SPELL_SELF_BUFF")
	this:RegisterEvent("CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF")
	this:RegisterEvent("CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF")
	this:RegisterEvent("ZONE_CHANGED_NEW_AREA")
	this:RegisterEvent("ZONE_CHANGED")
	this:RegisterEvent("ZONE_CHANGED_INDOORS")

	--to right tooltip handling need set the tooltip owner to none
	CS_Tooltip:SetOwner(UIParent, "ANCHOR_NONE")

	--hook chat frame if using event debug
	if CS_Event_Debug then
		local CS_OriginalChatHandlers
		for i = 1, 7, 1 do
			CS_OriginalChatHandlers = getglobal("ChatFrame" .. i).AddMessage
			getglobal("ChatFrame" .. i).AddMessage = 
			function(self, msg, r, g, b)
				CS_OriginalChatHandlers(self, msg.."|cffff33ff ["..tostring(event).."]", r, g, b)
			end
		end
	end

	--add slash commands
	SlashCmdList["COMBATSOUND"] = CS_ShowMenu
	SLASH_COMBATSOUND1 = "/coms"
	SLASH_COMBATSOUND2 = "/combatsound"

	-- add my options frame to the global UI panel list
	UIPanelWindows[CONFIG_FRAME] = {area = "center", pushable = 0, whileDead = 1}

	--set player name
	CS_Player = UnitName("player") .. " of " .. GetCVar("realmName")

	--if there is no config make a clear one
	if (not CSConfig) then
		 CSConfig = {}
	end
	
	--set the currentplayer config
	CS_PlayerData = CS_Config_GetPlayer()

	--set startup message
	CS_STARTUP_TEXT = CS_ISE(CS_START.."\n"..CS_ISENABLED)
	CombatSoundStartUPText:SetText(CS_STARTUP_TEXT)

	--initalize some arguments
	CS_MUSIC_FADER_STARTED_BOOLEN = false
	CS_STARTER_MESSAGE_DONE_BOOLEN = false
	CS_ATTACKING_BOOLEN = false
	CS_INCOMBAT_BOOLEN = false
	CS_REGEN_BOOLEN = true
	this.StartUpTimer = GetTime()
	CS_STARTUP_MESSAGE_INTERVAL = 10.0
	CS_STARTER_MESSAGE_RUNNABLE_BOOLEN = true
end

-----------------------------

--event handler
function CS_OnEvent()
	if (event == "ADDON_LOADED") then
		if (strlower(arg1) == "combatsound") then
			CS_Vars_Loaded = true
			CS_Initialize()
		end
	--Vars loaded, only load once (bug fix for some users)
	elseif (event == "VARIABLES_LOADED") then
		if (not CS_Vars_Loaded) then
			CS_Vars_Loaded = true
			CS_Initialize()
		end
	end

	--if CS is enabled
	if (CS_Get("ENABLE")) and (CS_INITALIZED_BOOLEN) then

		--setting combat flags
		if (event == "PLAYER_ENTER_COMBAT") then
			CS_ATTACKING_BOOLEN = true
			CS_INCOMBAT_BOOLEN = true

		elseif (event == "PLAYER_LEAVE_COMBAT") then
			CS_ATTACKING_BOOLEN = false
			if (CS_REGEN_BOOLEN) then
				CS_INCOMBAT_BOOLEN = false
			end

		elseif (event == "PLAYER_REGEN_DISABLED") then
			--in combat
			if (CS_Get("ENTERCOMBAT")) then
				CS_PlayFile(CS_SOUND_ENTER)
			end
			--play music
			if (CS_Get("MUSIC")) then
				CS_PlayRandomMusic()
			end
			CS_REGEN_BOOLEN = false
			CS_INCOMBAT_BOOLEN = true

		elseif (event == "PLAYER_REGEN_ENABLED") then
			--out of combat
			CS_MUSIC_FADER_ON = true
			if (CS_Get("LEAVECOMBAT")) then
				CS_PlayFile(CS_SOUND_LEAVE)
			end
			CS_REGEN_BOOLEN = true
			if (not CS_ATTACKING_BOOLEN) then
				CS_INCOMBAT_BOOLEN = false
			end

		--spell crit
 		elseif (event == "CHAT_MSG_SPELL_SELF_DAMAGE") then
			if (CS_Get("CRITS")) then
				local _,targetP1,_ = GlobalParser_ParseMessage(arg1, SPELLLOGCRITSELFOTHER)
				local _,targetP2,_,_ = GlobalParser_ParseMessage(arg1, SPELLLOGCRITSCHOOLSELFOTHER)
				if (targetP1 == CS_LAST_TARGETNAME) or (targetP2 == CS_LAST_TARGETNAME) then
					if (GetTime() - CRITICAL_TIMER >= 3) then
						CS_PlayRandom(CS_SOUND_CRITICAL)
						CRITICAL_TIMER = GetTime()
					end
				end
			end
			--shaman windfury
			if (CS_englishClass == "SHAMAN") and (CS_Get("WINDFURY")) then
				local attack,targetP3,_ = GlobalParser_ParseMessage(arg1, SPELLLOGSELFOTHER)
				if (targetP3 == CS_LAST_TARGETNAME) and (attack == "Windfury Attack") then
					if (GetTime() - WINDFURY_TIMER >= 3) then
						CS_PlayFile(CS_SOUND_WINDFURY)
						WINDFURY_TIMER = GetTime()
					end
				end
			end

		--crit hit
		elseif (event == "CHAT_MSG_COMBAT_SELF_HITS") and (CS_Get("CRITS")) then
			local targetP1,_ = GlobalParser_ParseMessage(arg1, COMBATHITCRITSELFOTHER)	--"You crit %s for %d."
			local _,targetP2,_ = GlobalParser_ParseMessage(arg1, "Your %s crits %s for %d.")
			local _,targetP3,_,_ = GlobalParser_ParseMessage(arg1, SPELLLOGCRITSCHOOLSELFOTHER)
			if (targetP1 == CS_LAST_TARGETNAME) or (targetP2 == CS_LAST_TARGETNAME) or (targetP3 == CS_LAST_TARGETNAME) then
				if (GetTime() - CRITICAL_TIMER >= 3) then
					CS_PlayRandom(CS_SOUND_CRITICAL)
					CRITICAL_TIMER = GetTime()
				end
			end
		--falling
			local healthDamage = GlobalParser_ParseMessage(arg1, VSENVIRONMENTALDAMAGE_FALLING_SELF)
			if (healthDamage and tonumber(healthDamage) > 1) then CS_PlayFile(CS_SOUND_FALL) end

		--healed crit by self and u heal crit others
		elseif (event == "CHAT_MSG_SPELL_SELF_BUFF") and (CS_Get("HEALCRITS")) then
			if (GlobalParser_ParseMessage(arg1, HEALEDCRITSELFSELF)) or (GlobalParser_ParseMessage(arg1, HEALEDCRITSELFOTHER)) then
				if (GetTime() - HEALCRIT_TIMER >= 3) then
					CS_PlayFile(CS_SOUND_HEAL)
					HEALCRIT_TIMER = GetTime()
				end
			end

		--healed crit by other
		elseif (event == "CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF") and (CS_Get("HEALCRITS")) then		
			if (GlobalParser_ParseMessage(arg1, HEALEDCRITOTHERSELF)) then
				if (GetTime() - HEALCRIT_TIMER >= 3) then
					CS_PlayFile(CS_SOUND_HEAL)
					HEALCRIT_TIMER = GetTime()
				end
			 end

		--warrior execute
		elseif (event == "UNIT_HEALTH") and (CS_Get("EXECUTE"))  and CS_LAST_TARGETNAME ~= "" then
			if (not UnitIsFriend("player","target")) then
				if (UnitHealth("target") < 20) and (UnitHealth("target") > 0) then 
					if (GetTime() - EXECUTE_TIMER >= 8) then
						CS_PlayFile(CS_SOUND_FINISH)
						EXECUTE_TIMER = GetTime()
					end
				end
			end

		--player combat messages 
		--get critical hit
		elseif (event == "UNIT_COMBAT") and ( arg1=="player") then
			if (CS_Get("GETCRITS")) and (arg2=="WOUND") and (arg3=="CRITICAL") then
				CS_PlayFile(CS_SOUND_OWNCRIT)			

			--we dodge an attack
			elseif (arg2=="DODGE") and (CS_Get("DODGE")) then
				CS_PlayFile(CS_SOUND_DODGE)

			--we parried an attack
			elseif (arg2=="PARRY") and (CS_Get("PARRY")) then
				CS_PlayFile(CS_SOUND_PARRY)

			end

		--hostile death praise
		elseif (event == "CHAT_MSG_COMBAT_HOSTILE_DEATH") and (CS_Get("KILLPRAISE")) then
			local targetP1 = GlobalParser_ParseMessage(arg1, UNITDIESOTHER)
			local targetP2 = GlobalParser_ParseMessage(arg1, SELFKILLOTHER)
			if ((targetP1 == CS_LAST_TARGETNAME) or (targetP2 == CS_LAST_TARGETNAME)) and (not CS_REGEN_BOOLEN) then
				if (GetTime() - KILLPRAISE_TIMER  >= 2) then
					CS_PlayRandom(CS_SOUND_TDEATH)
					KILLPRAISE_TIMER  = GetTime()
				end
			 end
			

		--target dodges
		elseif (event == "CHAT_MSG_COMBAT_SELF_MISSES") and (CS_Get("TARGETDODGE")) then
			if (GlobalParser_ParseMessage(arg1, VSDODGESELFOTHER)) then CS_PlayFile(CS_SOUND_DODGE_TARGET) end

		--player dead
		elseif (event == "PLAYER_DEAD") and (CS_Get("DEATH")) then
			CS_PlayRandom(CS_SOUND_DEATH)

		--combo points
		elseif (event == "PLAYER_COMBO_POINTS") and (CS_Get("COMBOPOINTS")) then
			CURR_COMBOPOINTS = GetComboPoints("player")
			--and for rogue, whos need only the FULLCOMBO notifycation
			if (CURR_COMBOPOINTS == 5) then
				CS_PlayFile(CS_SOUND_COMBOFULL)
			else
				if (CURR_COMBOPOINTS > 0) and (not CS_Get("COMBOFULL")) then
					CS_PlayFile(string.format(CS_SOUND_COMBO,CURR_COMBOPOINTS))			
				end
			end

		--out of combat and getting into a new zone bug
		elseif (event == "PLAYER_ENTERING_WORLD") then
			StopMusic()
			CS_INCOMBAT_BOOLEN = false

		--store targetID
		elseif (event == "PLAYER_TARGET_CHANGED") then
				if (not UnitName("target")) then
					CS_LAST_TARGETNAME = ""
				else
					if (not UnitIsFriend("player","target")) then
						CS_LAST_TARGETNAME = UnitName("target")
					else
						CS_LAST_TARGETNAME = ""
					end
				end

		--no more "elseif" - EVENTS
		end
	--ENABLED
	end
end

-----------------------------

function CS_OnUpdate(elapsed) 
	this.TimeSinceLastUpdate = this.TimeSinceLastUpdate + elapsed
	while (this.TimeSinceLastUpdate > CS_UpdateInterval) do
 
		--start message
		if (CS_STARTER_MESSAGE_RUNNABLE_BOOLEN and not InCombatLockdown()) then
			if (not CS_STARTER_MESSAGE_DONE_BOOLEN) then
				if (GetTime() - this.StartUpTimer >= CS_STARTUP_MESSAGE_INTERVAL) then
					if (CS_Get("STARTSOUND")) then CS_PlayFile(CS_SOUND_START) end
					UIFrameFlash(CombatSoundStartUPFrame, 2, 4,10, false, 0, 4)
					CS_STARTER_MESSAGE_DONE_BOOLEN = true
					this.StartUpTimer = GetTime()
				end
			else
				if (GetTime() - this.StartUpTimer >= 10) then
					if (CS_Get("STARTSOUND")) then CS_PlayFile(CS_SOUND_START_END) end
					UIFrameFlash(CombatSoundStartUPFrame, 0, 0.6, 0.6, false, 0, 0)
					CS_STARTER_MESSAGE_RUNNABLE_BOOLEN = false
					CS_INITALIZED_BOOLEN = true
					CombatSoundStartUPFrame:Hide()
				end
			end
		end

		--music fader
		if (CS_MUSIC_FADER_ON) and (not CS_INCOMBAT_BOOLEN) then
			if (not CS_MUSIC_FADER_STARTED_BOOLEN) then
				CS_MUSIC_VOLUME = GetCVar("Sound_MusicVolume")
				CS_Dvolume = CS_MUSIC_VOLUME
				CS_MUSIC_FADER_STARTED_BOOLEN = true
			end
			CS_Dvolume = CS_Dvolume-CS_MUSIC_VOLUME/48
			SetCVar("Sound_MusicVolume",CS_Dvolume)
			if (CS_Dvolume < 0.03) then
				StopMusic()
				CS_MUSIC_FADER_ON = false
				CS_MUSIC_FADER_STARTED_BOOLEN = false
				SetCVar("Sound_MusicVolume",CS_MUSIC_VOLUME)
			end
		end

	this.TimeSinceLastUpdate = this.TimeSinceLastUpdate - CS_UpdateInterval
	end
end
